{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 图像入门\n",
    "学习目标：\n",
    "- 图像的读取、显示、保存\n",
    "- 学习三个函数：cv2.imread(), cv2.imshow() , cv2.imwrite()\n",
    "- 使用 Matplotlib 来显示图像"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:47:36.951901Z",
     "start_time": "2019-03-06T08:47:36.557128Z"
    }
   },
   "outputs": [],
   "source": [
    "# 导入常用包\n",
    "#%matplotlib notebook\n",
    "import numpy as np\n",
    "import cv2\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 读取显示图像"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:47:46.051669Z",
     "start_time": "2019-03-06T08:47:41.994003Z"
    }
   },
   "outputs": [],
   "source": [
    "img = cv2.imread(\"./sample_img/img.jpg\", 0) # 1: 显示原始图， 0：灰度图  -1：加载图像包括 alpha 通道\n",
    "cv2.imshow(\"image\", img) # 第一个参数为显示窗口的名称，第二个参数是要显示的图像\n",
    "k = cv2.waitKey(0) & 0xFF # cv2.waitKey()  键盘绑定函数，等待键盘按下，以毫秒为计数单位，也可以设定特定按键点击。64 bit 的机器要 cv2.waitKey(0) & 0xFF\n",
    "if k == 27:         # 等待按下 ESC 键退出， \n",
    "    cv2.destroyAllWindows() # 销毁所有窗口，也可以用 cv2.destroyWindow() 销毁特定的窗口。\n",
    "elif k == ord('s'): # 指定某个按键按下后指定某种操作，如这里是保存\n",
    "    cv2.imwrite('image_write.png',img)\n",
    "    cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "结果：![](https://ws1.sinaimg.cn/large/acbcfa39gy1fzkfz55k4hj206l05aq3g.jpg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:47:49.041950Z",
     "start_time": "2019-03-06T08:47:47.790670Z"
    }
   },
   "outputs": [],
   "source": [
    "cv2.namedWindow(\"image_new\", cv2.WINDOW_NORMAL) # 创建一个新的窗口，这个窗口大小可以进行调节的\n",
    "cv2.imshow(\"image_new\", img)\n",
    "cv2.waitKey(0)\n",
    "cv2.destroyWindow(\"image_new\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://ws1.sinaimg.cn/large/acbcfa39gy1fzkfzs4gu2j20ed0dimy8.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 写图像（保存图像）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:47:52.753835Z",
     "start_time": "2019-03-06T08:47:52.531942Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cv2.imwrite(\"./sample_img/image_write.png\", img) # 保存图像，可以指定保存图像的格式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://ws1.sinaimg.cn/large/acbcfa39ly1fzkg0c5gl0j206q042dg2.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用 matplotlib 显示图像\n",
    "Matplotlib是一个用于Python的绘图库，它提供了多种绘图方法。在这里，将学习如何使用 Matplotlib 显示图像。可以使用 Matplotlib 放大图片，保存图片等。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:47:56.446694Z",
     "start_time": "2019-03-06T08:47:55.171426Z"
    },
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "img = cv2.imread(\"./sample_img/img.jpg\", 0)\n",
    "plt.imshow(img, cmap = 'gray', interpolation = 'bicubic') # interpolation 插值\n",
    "plt.xticks([])\n",
    "plt.yticks([])  # 隐藏 X、Y 坐标的刻度值\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://ws1.sinaimg.cn/large/acbcfa39ly1g0n8s46l98j209705rgmb.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "OpenCV 加载的彩色图像为 BGR 模式。但是 Matplotlib 以 RGB 模式显示。因此，如果使用 OpenCV 读取图像，Matplotlib 中的彩色图像将不能正确显示。\n",
    "\n",
    "以下是解决办法：对图像的模式进行转换，使之与 Matplotlib 或 OpenCV 匹配"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-02-25T08:54:02.949418Z",
     "start_time": "2019-02-25T08:54:01.025468Z"
    }
   },
   "outputs": [],
   "source": [
    "img_cv = cv2.imread(\"./sample_img/img.jpg\") # OpenCV 读取图像\n",
    "b, g, r = cv2.split(img_cv) # OpenCV 中图像显示是 BGR 模式，提取\n",
    "img_matplot = cv2.merge([r, g, b])\n",
    "plt.subplot(121)\n",
    "plt.imshow(img_cv) # 预计图像会是异常的\n",
    "plt.subplot(122)\n",
    "plt.imshow(img_matplot) # 预计是真实的图像\n",
    "plt.show()\n",
    "\n",
    "cv2.imshow('bgr image',img_cv) # 预计图像会是异常的\n",
    "cv2.imshow('rgb image',img_matplot) # 预计是真实的图像\n",
    "cv2.waitKey(0)\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://ws1.sinaimg.cn/large/acbcfa39ly1fzkg0z3gt3j20cp059tbh.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 更多资料\n",
    "\n",
    "[matplotlib 详细 API](https://matplotlib.org/api/pyplot_api.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 视频入门\n",
    "学习目标：\n",
    "- 显示视频、保存视频\n",
    "- 从相机进行捕获\n",
    "- cv2.VideoCapture(), cv2.VideoWriter() 函数使用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-01-26T05:29:19.191255Z",
     "start_time": "2019-01-26T05:29:18.943361Z"
    }
   },
   "source": [
    "#### 从相机捕获视频\n",
    "笔记本自带摄像头"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:48:22.513705Z",
     "start_time": "2019-03-06T08:48:13.899658Z"
    }
   },
   "outputs": [],
   "source": [
    "import cv2\n",
    "# 创建一个 VideoCapture 对象，参数是设备的索引即摄像机的编号或者 Video 的文件名\n",
    "# 这里的 0 是指第一台摄像机，以此类推\n",
    "cap = cv2.VideoCapture(0)\n",
    "while (True):\n",
    "    # while cap.isOpened():\n",
    "    # 一帧一帧的捕获\n",
    "    ret, frame = cap.read()\n",
    "\n",
    "    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n",
    "    # 显示\n",
    "    cv2.imshow(\"frame\", gray)  # 窗口名为 frame\n",
    "    if cv2.waitKey(1) & 0xFF == ord('q'):\n",
    "        break\n",
    "cap.release()  # 关闭视频文件或设备\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://ws1.sinaimg.cn/large/acbcfa39gy1fzkg242htxj20i90egtda.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`cap.read()` 返回一个bool (True/False)。如果帧被正确读取，它将为真。通过检查这个返回值来检查视频的结尾。\n",
    "\n",
    "有时，cap 可能没有初始化捕获。在这种情况下，这段代码显示错误。可以通过方法 `cap.isOpened()` 检查它是否初始化。如果为真，则 ok。否则使用 `cap.open()` 打开它。\n",
    "\n",
    "可以通过 `cap.get(propId)` 获取视频的一些属性，propId 值为：0 to 18。每个值代表视频的一个属性，详见 [Property Identifier](https://docs.opencv.org/2.4/modules/highgui/doc/reading_and_writing_images_and_video.html#videocapture-get) 也可以通过 `cap.set(propId, value)` 设置视频的属性。\n",
    "例如：可以通过 `cap.get(3)` 和 `cap.get(4)` 检查帧的宽和高，默认是 640x480。通过 `ret = cap.set(3,320)` 和 `ret = cap.set(4,240)` 将宽和高重新设定。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:48:32.778804Z",
     "start_time": "2019-03-06T08:48:27.137050Z"
    }
   },
   "outputs": [],
   "source": [
    "# 创建一个 VideoCapture 对象，参数是设备的索引即摄像机的编号或者 Video 的文件名\n",
    "# 这里的 0 是指第一台摄像机，以此类推\n",
    "cap = cv2.VideoCapture(0)\n",
    "while (True):\n",
    "    # while cap.isOpened():\n",
    "    # 一帧一帧的捕获\n",
    "    ret, frame = cap.read()\n",
    "    ret = cap.set(3, 320)\n",
    "    ret = cap.set(4, 240)\n",
    "    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n",
    "\n",
    "    cv2.imshow(\"frame\", gray)\n",
    "    if cv2.waitKey(1) & 0xFF == ord('q'):\n",
    "        break\n",
    "cap.release()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://ws1.sinaimg.cn/large/acbcfa39gy1fzkg30uoxgj209d07st9u.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 从文件进行播放"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:48:40.556332Z",
     "start_time": "2019-03-06T08:48:36.123880Z"
    }
   },
   "outputs": [],
   "source": [
    "cap = cv2.VideoCapture('./sample_img/vtest.avi')\n",
    "\n",
    "while(cap.isOpened()):\n",
    "    ret, frame = cap.read()\n",
    "\n",
    "    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n",
    "\n",
    "    cv2.imshow('frame', gray)\n",
    "    if cv2.waitKey(1) & 0xFF == ord('q'):\n",
    "        break\n",
    "\n",
    "cap.release()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://ws1.sinaimg.cn/large/acbcfa39ly1fzkg48a9dtj20vz0lc0ys.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**如果视频播放结束，还没按键按下，会出现错误。** 改进如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:48:46.770759Z",
     "start_time": "2019-03-06T08:48:43.453666Z"
    }
   },
   "outputs": [],
   "source": [
    "import cv2\n",
    "cap = cv2.VideoCapture('./sample_img/vtest.avi')\n",
    "\n",
    "while(cap.isOpened()):\n",
    "    ret, frame = cap.read()\n",
    "\n",
    "    if ret == True:\n",
    "        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n",
    "        cv2.imshow('frame', gray)\n",
    "    if ret == False:\n",
    "        # cap.release() # 释放掉开启的视频\n",
    "        # print(\"1\") # 测试\n",
    "\n",
    "        cv2.waitKey(0)  # 暂停在最后一帧\n",
    "        break  # 关闭窗口后退出\n",
    "    if cv2.waitKey(1) & 0xFF == ord('q'):\n",
    "        break\n",
    "\n",
    "cap.release()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "改进以后，程序会一直监测视频是否到最后一帧，若是最后一帧，则 ret 为 False ，暂停在最后一帧并且在关闭窗口后退出"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 保存视频"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-02-25T08:55:00.002496Z",
     "start_time": "2019-02-25T08:54:53.854017Z"
    }
   },
   "outputs": [],
   "source": [
    "cap = cv2.VideoCapture(0)\n",
    "\n",
    "# Define the codec and create VideoWriter object\n",
    "# cv2.VideoWriter_fourcc('X','V','I','D') 功能一样\n",
    "fourcc = cv2.VideoWriter_fourcc(*'XVID')\n",
    "\n",
    "# 创建 VideoWriter 对象，指定输出文件名 output.avi， FourCC 代码，传递每秒帧数和帧大小\n",
    "out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480))\n",
    "\n",
    "while(cap.isOpened()):\n",
    "    ret, frame = cap.read()\n",
    "    if ret == True:\n",
    "        # 对每一帧进行翻转\n",
    "        frame = cv2.flip(frame, 0)  # 注释见下\n",
    "\n",
    "        # write the flipped frame\n",
    "        out.write(frame)\n",
    "\n",
    "        cv2.imshow('frame', frame)\n",
    "        if cv2.waitKey(1) & 0xFF == ord('q'):\n",
    "            break\n",
    "    else:\n",
    "        break\n",
    "\n",
    "# Release everything if job is finished\n",
    "cap.release()\n",
    "out.release()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-01-26T06:16:55.952887Z",
     "start_time": "2019-01-26T06:16:55.866935Z"
    }
   },
   "source": [
    "FourCC 是一个 4 字节的代码，用于指定视频编解码器，**依赖于平台**，到时看具体平台进行选择。更多 FourCC 代码见 [官网](http://www.fourcc.org/)\n",
    "\n",
    "`cv2.flip(src, flipCode[, dst]) → dst`: flipCode: 0表示绕 x 轴翻转，正值(例如，1)表示绕 y 轴翻转。负值(例如 -1)表示在两个轴上翻转。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 更多资料\n",
    "[opencv documentation](https://docs.opencv.org/2.4/index.html#)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### OpenCV 绘图功能\n",
    "学习目标:\n",
    "- 使用 OpenCV 绘制不同几何形状\n",
    "- cv2.line(), cv2.circle() , cv2.rectangle(), cv2.ellipse(), cv2.putText()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以下图像都用 matplotlib 绘制"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 函数共有参数说明\n",
    "- img: 要操作的图像\n",
    "- color：绘制形状的颜色， RGB 传入元组如(255, 255, 255)， 灰度值只需传入标量\n",
    "- thickness：线或圆等的厚度。如果对圆形等闭合图形传递 -1 ，则填充形状。默认为 1\n",
    "- lineType：线的类型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 绘制各种形状"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:49:04.112809Z",
     "start_time": "2019-03-06T08:49:02.280841Z"
    },
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# 需要给定直线的起始和结束坐标\n",
    "\n",
    "# 创建一个黑色的画布\n",
    "img = np.zeros((512, 512, 3), np.uint8)\n",
    "\n",
    "# 绘制坐标 (0, 0) -> (510, 128) 直线 蓝色，厚度为 5px\n",
    "img = cv2.line(img, (0, 0), (511, 511), (255, 0, 0), 5)  # OpenCV 为 BGR 模式\n",
    "# 绘制长方形，起始和终点坐标，颜色，厚度\n",
    "img = cv2.rectangle(img, (384, 10), (505, 120), (0, 255, 0), 3)\n",
    "# 绘制圆形，给定圆心，半径，最后 -1 为图形填充\n",
    "img = cv2.circle(img, (447, 63), 63, (0, 0, 255), -1)\n",
    "# 绘制椭圆，椭圆心，长轴，短轴，角度，起始结束角，填充\n",
    "img = cv2.ellipse(img, (256, 256), (100, 50), 0, 0, 180, 255, -1)\n",
    "# 绘制多边形，给定多边形的顶点坐标\n",
    "pts = np.array([[50, 50], [40, 40], [60, 40], [60, 100]], np.int32)\n",
    "pts = pts.reshape((-1, 1, 2))\n",
    "# 若第三个参数为 False，则得到连接所有点的折线，而不是一个闭合的形状。该函数可以用来绘制多条直线\n",
    "img = cv2.polylines(img, [pts], True, (0, 255, 255))\n",
    "# 添加文字到图形中\n",
    "font = cv2.FONT_HERSHEY_SIMPLEX  # 指定字体\n",
    "cv2.putText(img, 'OpenCV', (10, 500), font, 4, (255, 255, 255),\n",
    "            2, cv2.LINE_AA)  # 绘制的图像，文字，文字左下角的坐标,字体，字体颜色，厚度等\n",
    "\n",
    "cv2.imshow(\"diff type\", img)\n",
    "k = cv2.waitKey(0) & 0xFF\n",
    "if k == 27:\n",
    "    cv2.destroyAllWindows()\n",
    "\n",
    "\n",
    "b, g, r = cv2.split(img)\n",
    "img = cv2.merge([r, g, b])\n",
    "plt.subplot(121)\n",
    "plt.xticks([])\n",
    "plt.yticks([])\n",
    "plt.imshow(img)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://ws1.sinaimg.cn/large/acbcfa39gy1fzkg6y64ejj20ep0fcgly.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "作业：绘制 OpenCV 图标 ![](https://opencv-python-tutroals.readthedocs.io/en/latest/_static/opencv-logo-white.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-01-26T12:12:41.816773Z",
     "start_time": "2019-01-26T12:12:41.809778Z"
    }
   },
   "source": [
    "#### 更多资料\n",
    "- [绘制椭圆时角度的确定](http://answers.opencv.org/question/14541/angles-in-ellipse-function/)\n",
    "- [本小节见此](https://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html)\n",
    "- [Ascii 表](http://www.asciitable.com/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 鼠标作为画笔\n",
    "学习目标：\n",
    "- 处理鼠标事件\n",
    "- cv2.setMouseCallback()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 简单 Demo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "首先，创建一个鼠标回调函数，该函数在鼠标事件发生时执行。鼠标事件可以是任何与鼠标相关的东西，如左键向下、左键向上、左键双击等。它为每个鼠标事件提供坐标 (x,y)。有了这个事件和位置，我们可以做任何我们想做的事情。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:49:14.591765Z",
     "start_time": "2019-03-06T08:49:14.582769Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['EVENT_FLAG_ALTKEY',\n",
       " 'EVENT_FLAG_CTRLKEY',\n",
       " 'EVENT_FLAG_LBUTTON',\n",
       " 'EVENT_FLAG_MBUTTON',\n",
       " 'EVENT_FLAG_RBUTTON',\n",
       " 'EVENT_FLAG_SHIFTKEY',\n",
       " 'EVENT_LBUTTONDBLCLK',\n",
       " 'EVENT_LBUTTONDOWN',\n",
       " 'EVENT_LBUTTONUP',\n",
       " 'EVENT_MBUTTONDBLCLK',\n",
       " 'EVENT_MBUTTONDOWN',\n",
       " 'EVENT_MBUTTONUP',\n",
       " 'EVENT_MOUSEHWHEEL',\n",
       " 'EVENT_MOUSEMOVE',\n",
       " 'EVENT_MOUSEWHEEL',\n",
       " 'EVENT_RBUTTONDBLCLK',\n",
       " 'EVENT_RBUTTONDOWN',\n",
       " 'EVENT_RBUTTONUP']"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 列出鼠标处理的事件\n",
    "events = [i for i in dir(cv2) if 'EVENT' in i]\n",
    "events"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:49:16.983393Z",
     "start_time": "2019-03-06T08:49:15.515234Z"
    }
   },
   "outputs": [],
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "# 功能函数，在鼠标处左键双击，绘制白色填充的圆\n",
    "def draw_circle(event, x, y, flags, param):\n",
    "    if event == cv2.EVENT_LBUTTONDBLCLK:\n",
    "        cv2.circle(img, (x, y), 100, (255, 255, 255), -1)\n",
    "\n",
    "\n",
    "# 创建一个黑色画布\n",
    "img = np.zeros((512, 512, 3), np.uint8)\n",
    "cv2.namedWindow(\"image\")\n",
    "# 创建鼠标回调函数，绑定功能函数\n",
    "cv2.setMouseCallback(\"image\", draw_circle)\n",
    "\n",
    "while(1):\n",
    "    cv2.imshow(\"image\", img)\n",
    "    if cv2.waitKey(20) & 0xFF == 27:\n",
    "        break\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://ws1.sinaimg.cn/large/acbcfa39gy1fzkg7jvqtyj20ep0fc3yl.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-01-26T12:56:48.302689Z",
     "start_time": "2019-01-26T12:56:44.399925Z"
    }
   },
   "source": [
    "#### 高级 Demo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在我们要做更多更好的应用。在这里，通过拖动鼠标来绘制矩形或圆形(这取决于我们选择的模式)，就像在 Paint 应用程序中所做的那样。我们的鼠标回调函数有两部分，一部分用来画矩形，另一部分用来画圆。这个具体的例子将非常有助于创建和理解一些交互式应用程序，如**对象跟踪，图像分割等。**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:49:20.933120Z",
     "start_time": "2019-03-06T08:49:19.709823Z"
    }
   },
   "outputs": [],
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "\n",
    "drawing = False # 鼠标按下为 True\n",
    "mode = True # 按键 'm' 切换模式\n",
    "ix, iy = -1, -1\n",
    "\n",
    "\n",
    "def draw(event, x, y, flags, param):\n",
    "    global ix, iy, drawing, mode\n",
    "\n",
    "    if event == cv2.EVENT_LBUTTONDOWN: # 鼠标放下\n",
    "        drawing = True\n",
    "        ix, iy = x, y # 鼠标放下时的坐标\n",
    "\n",
    "    elif event == cv2.EVENT_MOUSEMOVE: # 鼠标移动\n",
    "        if drawing == True:\n",
    "            if mode == True:\n",
    "                cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)\n",
    "            else:\n",
    "                cv2.circle(img, (x, y), 5, (0, 0, 255), -1)\n",
    "\n",
    "    elif event == cv2.EVENT_LBUTTONUP: # 鼠标提起，结束绘制\n",
    "        drawing = False\n",
    "        # ------------- 中间这一段要不要？\n",
    "        if mode == True:\n",
    "            cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)\n",
    "        else:\n",
    "            cv2.circle(img, (x, y), 5, (0, 0, 255), -1)    \n",
    "        # -------------\n",
    "\n",
    "\n",
    "img = np.zeros((512, 512, 3), np.uint8)\n",
    "cv2.namedWindow(\"image\")\n",
    "cv2.setMouseCallback(\"image\", draw) # 功能绑定\n",
    "\n",
    "while(1):\n",
    "    cv2.imshow(\"image\", img)\n",
    "    k = cv2.waitKey(1) & 0xFF\n",
    "    if k == ord('m'): # 按键 'm' 切换模式\n",
    "        mode = not mode\n",
    "    elif k == 27:\n",
    "        break\n",
    "        \n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://ws1.sinaimg.cn/large/acbcfa39ly1fzkg8f7ktpj20ep0fc0ss.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 轨迹栏作为调色板\n",
    "学习目标：\n",
    "- 将轨迹栏绑定到 OpenCV 窗口\n",
    "- cv2.getTrackbarPos(), cv2.createTrackbar()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-01-26T14:49:37.430668Z",
     "start_time": "2019-01-26T14:48:37.448967Z"
    }
   },
   "source": [
    "#### Demo\n",
    "创建简单的应用程序，通过滑动轨迹条调节 BGR 的值从而改变画布颜色，初始颜色为黑色。\n",
    "\n",
    "cv2.createTrackbar() 函数，第一个参数是 trackbar 名称，第二个参数是将用作创建的 trackbar 的父窗口的名称，第三个参数是默认值，第四个参数是最大值，第五个参数是回调函数，每次 trackbar 值发生变化时都会执行回调函数。回调函数总是有一个默认参数，即 trackbar 位置。在我们的例子中，函数什么也不做，所以我们只是传递。\n",
    "\n",
    "trackbar 的另一个重要应用是将其用作按钮或开关。默认情况下，OpenCV 没有按钮功能。所以你可以使用 trackbar 来获得这样的功能。在我们的应用程序中，我们已经创建了一个开关，在这个开关中应用程序只在开关打开时才工作，否则屏幕总是黑色的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:49:25.740354Z",
     "start_time": "2019-03-06T08:49:24.372144Z"
    }
   },
   "outputs": [],
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "\n",
    "\n",
    "def nothing(x):\n",
    "    pass\n",
    "\n",
    "\n",
    "img = np.zeros((300, 512, 3), np.uint8)\n",
    "cv2.namedWindow(\"image\")\n",
    "\n",
    "cv2.createTrackbar('R', 'image', 0, 255, nothing)\n",
    "cv2.createTrackbar('G', 'image', 0, 255, nothing)\n",
    "cv2.createTrackbar('B', 'image', 0, 255, nothing)\n",
    "\n",
    "switch = '0 : OFF \\n1 : ON'\n",
    "cv2.createTrackbar(switch, 'image', 0, 1, nothing)\n",
    "\n",
    "while(1):\n",
    "    cv2.imshow('image', img)\n",
    "    k = cv2.waitKey(1) & 0xFF\n",
    "    if k == 27:\n",
    "        break\n",
    "    r = cv2.getTrackbarPos('R', 'image')\n",
    "    g = cv2.getTrackbarPos('G', 'image')\n",
    "    b = cv2.getTrackbarPos('B', 'image')\n",
    "    s = cv2.getTrackbarPos(switch, 'image')\n",
    "\n",
    "    if s == 0:\n",
    "        img[:] = 0\n",
    "    else:\n",
    "        img[:] = [b, g, r]\n",
    "\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://ws1.sinaimg.cn/large/acbcfa39ly1fzkg8wan3cj20ep0ga74d.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-01-26T15:41:51.789334Z",
     "start_time": "2019-01-26T15:41:46.382426Z"
    }
   },
   "source": [
    "#### 练习\n",
    "创建一个画笔颜色和笔刷半径可调的滑动轨迹条"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-03-06T08:49:28.996483Z",
     "start_time": "2019-03-06T08:49:27.626270Z"
    }
   },
   "outputs": [],
   "source": [
    "import cv2\n",
    "import numpy as np\n",
    "\n",
    "\n",
    "def nothing(x):\n",
    "    pass\n",
    "\n",
    "\n",
    "radius_t = 1\n",
    "bt, gt, rt = 255, 255, 255\n",
    "\n",
    "\n",
    "def draw_circle(event, x, y, radius, b=255, g=255, r=255):\n",
    "    global radius_t, bt, gt, rt\n",
    "    radius = radius_t\n",
    "    b, g, r = bt, gt, rt\n",
    "    if event == cv2.EVENT_LBUTTONDBLCLK:\n",
    "        cv2.circle(img, (x, y), radius, (b, g, r), -1)\n",
    "\n",
    "\n",
    "img = np.zeros((1366, 768, 3), np.uint8)\n",
    "cv2.namedWindow(\"image\")\n",
    "\n",
    "# --------- 画笔颜色\n",
    "cv2.createTrackbar('brush_radius', 'image', 1, 10, nothing)\n",
    "cv2.createTrackbar('pen_B', 'image', 0, 255, nothing)\n",
    "cv2.createTrackbar('pen_G', 'image', 0, 255, nothing)\n",
    "cv2.createTrackbar('pen_R', 'image', 0, 255, nothing)\n",
    "\n",
    "\n",
    "# 创建鼠标回调函数，绑定功能函数\n",
    "cv2.setMouseCallback(\"image\", draw_circle)\n",
    "\n",
    "while(1):\n",
    "    cv2.imshow('image', img)\n",
    "    k = cv2.waitKey(1) & 0xFF\n",
    "    if k == 27:\n",
    "        break\n",
    "    \n",
    "    brush_radius = cv2.getTrackbarPos('brush_radius', 'image')\n",
    "    pen_B = cv2.getTrackbarPos('pen_B', 'image')\n",
    "    pen_G = cv2.getTrackbarPos('pen_G', 'image')\n",
    "    pen_R = cv2.getTrackbarPos('pen_R', 'image')\n",
    "\n",
    "    # 对鼠标函数参数进行赋值\n",
    "    radius_t = brush_radius \n",
    "    bt, gt, rt = pen_B, pen_G, pen_R\n",
    "\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://ws1.sinaimg.cn/large/acbcfa39ly1fzkg9qsow0j20lt0kwq3a.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 更多资料\n",
    "[createtrackbar API](https://docs.opencv.org/2.4/modules/highgui/doc/user_interface.html?highlight=createtrackbar)"
   ]
  }
 ],
 "metadata": {
  "hide_input": false,
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.6"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {
    "height": "210px",
    "width": "305px"
   },
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "165px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
